import { e, style } from "../utils/html";
import { app } from "../utils/global";
import { default_tile_8x8 } from "../utils/const";
import { TileSelector } from "../components/TileSelector";
import { button } from "../components/Button";
import overlay from "../components/Overlay";
import { saveToClipboard, save, toBase64, toPythonExpression, openLocalFile } from "../utils/file";
import { PageClass } from "./PageClass";
import { getText } from "../utils/translate";
// style
const pageContent = {
  width: "100%",
  maxWidth: "720px",
  margin: "0 auto",
}
const tileSelectorCanvas = {
  width: "80%",
  margin: "0 10%",
}

export class PageTileSelector extends PageClass{
  constructor(){
    super();
    this.__setupElement(8, 8, 256);
    this.__updateGlobalTileMapSelector = this.__updateGlobalTileMapSelector.bind(this);
    this.__listenSelectTileDataChange = this.__listenSelectTileDataChange.bind(this);
    // register listener
    app.register(app.k.EVENT_SELECT_TILE_DATA_CHANGE, this.__listenSelectTileDataChange);
    this.__clearGlobalTileMapSelector();
  }

  __setupElement(w=8, h=8, count=256, map=undefined){
    let blockSize = Math.ceil(w / 8) * h;
    let datasize = blockSize * count
    if (map == undefined){
      map = new Uint8Array(datasize);
      for (let i=0; i<map.length; i++){
        if (w == 8 && h == 8){
          map[i] = default_tile_8x8[i % default_tile_8x8.length];
        }else{
          map[i] = 0;
        }
      }
    }
    //
    this.tileMap = new TileSelector(
      map.slice(0, datasize),
      w, h, 4, 16, [0,0,0], [128,255,128], 128,
      (index, tileMap)=>{
        app.set(app.k.SELECT_TILE_INDEX, index);
        app.set(app.k.SELECT_TILE_DATA, tileMap.getTileBytes(index));
        app.set(app.k.SELECT_TILE_WIDTH, tileMap.blockWidth);
        app.set(app.k.SELECT_TILE_HEIGHT, tileMap.blockHeight);
        app.set(app.k.EVENT_SELECT_TILE_CHANGE, true); // triger TileEditor update
      }
    );
    style(this.tileMap.element, {width:"100%"});
    // init or create new element
    if (this.canvasArea instanceof HTMLElement){
      this.canvasArea.removeChild(this.canvasArea.children[0]);
      this.canvasArea.appendChild(this.tileMap.element);
      return;
    }
    this.canvasArea = e("div", {style: tileSelectorCanvas}, this.tileMap.element)
    this.element = e("div",{style: pageContent},
      e("p", {style:{width:"100%",textAlign:"center"}}, getText("tile_selector_top_tips")),
      // button bar
      e("div", {style:{display:"flex",flexDirection:"column",alignItems:"center"}},
        e("div", {style:{display:"flex",justifyContent:"space-around",alignItems:"center",width:"100%"}},
          button(getText("tile_selector_op_btn_new"), this.__btnNewTileMap.bind(this)),
          button(getText("map_editor_op_button_open_map"), this.__btnOpenTileMap.bind(this)),
          button(getText("map_editor_op_button_save_map"), this.__btnSaveTileMap.bind(this)),
        ),
      ),
      this.canvasArea,
    );
  }

  __updateGlobalTileMapSelector(){
    let index = app.get(app.k.SELECT_TILE_INDEX, -1);
    app.set(app.k.EVENT_CURRENT_TILE_MAP_SELECTOR_CHANGE, index); // triger TileEditor change
  }

  __clearGlobalTileMapSelector(){
    app.set(app.k.CURRENT_TILE_MAP_SELECTOR, this.tileMap);
    app.set(app.k.EVENT_CURRENT_TILE_MAP_SELECTOR_CHANGE, -1); // triger TileEditor change
  }

  __clearGlobalTileSelect(){
    app.set(app.k.SELECT_TILE_INDEX, -1);
    app.set(app.k.SELECT_TILE_DATA, new Uint8Array(this.tileMap.blockDataSize));
    app.set(app.k.SELECT_TILE_WIDTH, this.tileMap.blockWidth);
    app.set(app.k.SELECT_TILE_HEIGHT, this.tileMap.blockHeight);
    app.set(app.k.EVENT_SELECT_TILE_CHANGE, true); // triger TileEditor update
  }

  __listenSelectTileDataChange(){
    let index = app.get(app.k.SELECT_TILE_INDEX);
    let data = app.get(app.k.SELECT_TILE_DATA);
    this.tileMap.setTileBytes(index, data);
    this.__updateGlobalTileMapSelector();
  }
  
  // button callback
  async __btnNewTileMap(){
    let ask = await overlay.confirm(getText("tile_selector_text_prompt_new_tile_map"));
    if (!ask) return;
    let width = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_width"));
    let height = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_height"));
    let count = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_count"));
    try{
      width = Number.parseInt(width);
      height = Number.parseInt(height);
      count = Number.parseInt(count);
      if (!Number.isInteger(width)||!Number.isInteger(height)|| width<8 || width>64 || width%8!=0 || height<8 || height>64 || count < 8 || count > 256){
        throw new Error(getText("tile_selector_text_error_tile_map_size_error"));
      }
      this.__setupElement(width, height, count);
      this.__clearGlobalTileMapSelector();
      this.__clearGlobalTileSelect();
    }catch(err){
      overlay.alert(getText("tile_selector_text_error_tile_map_create_failed"));
      console.error(err);
    }
  }
  async __btnOpenTileMap(){
    let ask = await overlay.confirm(getText("tile_selector_text_prompt_open_tile_map"));
    if (!ask) return;
    let file = await openLocalFile();
    if (! file instanceof File){
      return;
    }
    let info = await overlay.confirm(getText("tile_selector_text_prompt_map_has_info"));
    try{
      let buffer = await file.arrayBuffer();
      let data = new Uint8Array(buffer);
      let width, height;
      // without basic info
      if (info){
        width = data[0];
        height = data[1];
        data = data.slice(2);
      }else{
        let widthText = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_width"));
        let heightText = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_height"));
        width = Number.parseInt(widthText);
        height = Number.parseInt(heightText);
        if (!Number.isInteger(width)||!Number.isInteger(height)|| width<8 || width>64 || width%8!=0 || height<8 || height>64){
          throw new Error(getText("tile_selector_text_error_tile_map_size_error"));
        }
      }
      let blockSize = Math.ceil(width / 8) * height;
      let count = Math.floor(data.length / blockSize)
      this.__setupElement(width, height, count, data);
    }catch(err){
      overlay.alert(getText("tile_selector_text_error_tile_map_open_failed"));
      console.error(err);
    }
  }

  async __btnSaveTileMap(){
    let name = await overlay.prompt(getText("tile_selector_text_prompt_choose_filename"));
    if (!name) return;
    let info = await overlay.confirm(getText("tile_selector_text_prompt_tile_map_with_info"));
    let data = this.tileMap.buffer;
    if (info) {
      let tdata = new Uint8Array(data.length+2);
      tdata.set(data, 2);
      tdata[0] = this.tileMap.blockWidth;
      tdata[1] = this.tileMap.blockHeight;
      data = tdata;
    }
    let method
    while (!["file","base64","python"].includes(method)){
      method = await overlay.prompt(getText("tile_selector_text_prompt_tile_map_save_format"));
    }
    let text = "";
    switch(method){
      case "file": save(data, `${name}.${info?"tiles":"raw"}`); return;
      case "base64": saveToClipboard(text = toBase64(data)); break;
      case "python": saveToClipboard(text = toPythonExpression(data)); break;
      default: break;
    }
    overlay.alert(`${getText("tile_selector_text_alert_copy")}:\n${text}`);
  }
  // onMount(){console.log("enter")};
  // onUnmount(){console.log("leave")};
}